<?php

declare(strict_types=1);

namespace App\Services;

use App\Helpers\File;
use App\Repositories\UserRepository;
use App\Validations\UserValidation;
use InvalidArgumentException;

class UserService extends BaseService
{
    /**
     * Obtiene una instancia de las reglas de validación de los usuarios.
     */
    private function userValidation(): UserValidation
    {
        return new UserValidation;
    }

    /**
     * Obtiene una instancia del repositorio de los usuarios.
     */
    private function userRepository(): UserRepository
    {
        return new UserRepository;
    }

    /**
     * Registra la información de un nuevo usuario.
     */
    public function register(array $data): string
    {
        $fields = array_keys($data);
        $userValidation = $this->userValidation();

        // Valida la información del usuario.
        $this->gump()->validation_rules($userValidation->getRules($fields, true));
        $this->gump()->filter_rules($userValidation->getFilters($fields));

        $data = $this->gump()->run($data);

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('La información de registro del usuario es incorrecta');
        }

        $userRepository = $this->userRepository();

        // Comprueba que los campos sean únicos.
        foreach (['username', 'email'] as $field) {
            if ($userRepository->findIdByColumn($field, $data[$field])) {
                throw new InvalidArgumentException(sprintf('El campo "%s" debe ser único', $field));
            }
        }

        unset($data['confirm_password']);

        return $userRepository->insert($data);
    }

    /**
     * Modifica la información de un usuario.
     */
    public function update(string $id, array $data): void
    {
        $fields = array_keys($data);
        $userValidation = $this->userValidation();

        // Obtiene las reglas de validación obligatorias.
        $rules = $userValidation->getRules(['id', 'username', 'email'], true);

        // Valida la información del usuario.
        $this->gump()->validation_rules(array_merge($userValidation->getRules($fields), $rules));
        $this->gump()->filter_rules($userValidation->getFilters($fields));

        $data = $this->gump()->run(array_merge($data, ['id' => $id]));

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('La información de modificación del usuario es incorrecta');
        }

        $userRepository = $this->userRepository();

        // Comprueba que los campos sean únicos.
        foreach (['username', 'email'] as $field) {
            $otherId = $userRepository->findIdByColumn($field, $data[$field]);

            if (isset($otherId) && $id !== $otherId) {
                throw new InvalidArgumentException(sprintf('El campo "%s" debe ser único', $field));
            }
        }

        // Elimina los campos con strings vacíos.
        foreach ($fields as $field) {
            if (empty($data[$field]) && is_string($data[$field])) {
                unset($data[$field]);
            }
        }

        // Elimina campos innecesarios para modificar.
        foreach (['id', 'confirm_password'] as $field) {
            unset($data[$field]);
        }

        $photo = $data['photo'] ?? null;

        // Genera un nombre único para la foto.
        $data['photo'] = isset($photo) && $photo['error'] === UPLOAD_ERR_OK
            ? File::generateRandomName($photo['name']) : null;

        if (empty($data['photo'])) {
            unset($data['photo']);
        }

        // Almacena la nueva foto del contacto.
        if (isset($data['photo'])) {
        }

        $userRepository->update($id, $data);
    }
}
